// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: implementation of CXmlState.
//   $Id$
// XmlState.cpp : Implementation of CXmlState


#include "stdafx.h"
#include "XmlState.h"

#include "boundnode.h"
#include "namespaces.h"
#include <new>
#include "eventmsg.h"
#include "XFormsApp.h"
extern CXFormsApp theApp;
// CXmlState

STDMETHODIMP CXmlState::relevant(IXMLDOMNodeList * pNl, BOOL * bIsRelevant)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	CBoundNode * pBoundNode = 0;
	HRESULT hr = S_OK;
	try {
		if(pNl && bIsRelevant) {
			if(m_bRelevant != VARIANT_FALSE) {
				hr = GetBoundNode(pNl,0,pBoundNode);
				if(S_OK == hr)
					*bIsRelevant = pBoundNode->isRelevant();
				 else 
					*bIsRelevant = TRUE;
			} else {
				*bIsRelevant = TRUE;
			}
		} else {
			hr = E_INVALIDARG;
		}
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	::safeRelease(pBoundNode);
	return hr;
}

STDMETHODIMP CXmlState::valid(IXMLDOMNodeList * pNl,BOOL * bIsValid)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	HRESULT hr = S_OK;
	try {
		if(pNl && bIsValid) {
			if(m_bValidate != VARIANT_FALSE) {
				CBoundNode * pBoundNode =0;
				hr = GetBoundNode(pNl,0,pBoundNode);
				if(S_OK == hr) {
					*bIsValid = pBoundNode->isValid();
					if(!*bIsValid)
						m_bWholeValid = false;
				} else
					*bIsValid = TRUE;
				::safeRelease(pBoundNode);
			} else {
				*bIsValid = true;
			}
		} else {
			hr = E_INVALIDARG;
		}
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	#ifdef _DEBUG
	if(false)
	{
		CComPtr<IXMLDOMNode> pNode;
		pNl->get_item(0,&pNode);
		long l= 0;
		pNl->get_length(&l);
		CComBSTR s;
		pNode->get_xml(&s);
		::MessageBoxW(0,s,0,0);
	}
	#endif
	return hr;
}

STDMETHODIMP CXmlState::required(IXMLDOMNodeList * pNl , BOOL * bIsRequired)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	CBoundNode * pBoundNode = 0;
	HRESULT hr = E_FAIL;
	try {
		hr = GetBoundNode(pNl,0,pBoundNode);
		if(S_OK == hr)
			*bIsRequired = pBoundNode->isRequired();
		else
			*bIsRequired = FALSE;
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	::safeRelease(pBoundNode);
	return hr;
}

STDMETHODIMP CXmlState::readOnly(IXMLDOMNodeList * pNl, BOOL * bIsReadOnly)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	CBoundNode * pBoundNode = 0;
	HRESULT hr = E_FAIL;
	try {
		hr = GetBoundNode(pNl,0,pBoundNode);
		if(S_OK == hr)
			*bIsReadOnly = pBoundNode->isReadonly();
		 else
			*bIsReadOnly = FALSE;
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	::safeRelease(pBoundNode);
	return hr;
}

//Returns the nth node in the nodelist as a bound node, 
//	if no such node exists in the map, returns S_FALSE;
HRESULT CXmlState::GetBoundNode(IXMLDOMNodeList * pNl, long lIndex, CBoundNode *& rpBoundNode)
{
	HRESULT hr = S_FALSE;

	CComPtr<IXMLDOMNode> pNode;
	pNl->get_item(lIndex,&pNode);
	rpBoundNode = CBoundNode::GetBoundNode(pNode,0,true);
	if(rpBoundNode)
		hr = S_OK;
	return hr;
}

STDMETHODIMP CXmlState::isOfType(IXMLDOMNodeList* pNl, BSTR bsURI, BSTR bsName , BOOL * bResult)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	CBoundNode * pBoundNode = 0;
	HRESULT hr = E_FAIL;
	try {
		hr = GetBoundNode(pNl,0,pBoundNode);
		if(S_OK == hr) {
			SQName qn = {bsURI,bsName};
			*bResult = pBoundNode->isOneOfType(&qn,1)?TRUE:FALSE;
		} else {
			//String is the default binding type of a node
			if(wcscmp(ws_NSURI_XSD,bsURI) && wcscmp(bsName,L"string") == 0)
				*bResult = TRUE;
			else
				*bResult = FALSE;
		}
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	::safeRelease(pBoundNode);
	return hr;
}

// IXmlStateManager 
STDMETHODIMP CXmlState::get_bValidate( VARIANT_BOOL *  pbValidate) {
	*pbValidate = m_bValidate;
	return S_OK;
}

STDMETHODIMP CXmlState::put_bValidate( VARIANT_BOOL  bValidate) {
	m_bValidate = bValidate;
	return S_OK;
}

STDMETHODIMP CXmlState::isValid( VARIANT_BOOL *  pbIsValid) {
	*pbIsValid = (m_bWholeValid == FALSE) ? VARIANT_FALSE : VARIANT_TRUE;
	return S_OK;
}

STDMETHODIMP CXmlState::get_bRelevant( VARIANT_BOOL *  pbRelevant) {
	*pbRelevant = m_bRelevant;
	return S_OK;
}

STDMETHODIMP CXmlState::put_bRelevant( VARIANT_BOOL  bRelevant) {
	m_bRelevant = bRelevant;
	return S_OK;
}

// IXmlState2
STDMETHODIMP CXmlState::valid(IXMLDOMNodeList *pNodeList, VARIANT_BOOL bTestAllNodes, VARIANT_BOOL *pbValid)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	HRESULT hr = S_OK;

	if(pbValid) {
		if(bTestAllNodes == VARIANT_TRUE) {
			if(pNodeList) {
				if(m_bValidate != VARIANT_FALSE) {
					bool bNodesAreValid = true;

					long nNodes = 0;
					pNodeList->get_length(&nNodes);
					for(long i = 0; i < nNodes; ++i) {
						CBoundNode *pBoundNode = 0;
						if(GetBoundNode(pNodeList, i, pBoundNode) == S_OK && !pBoundNode->isValid()) {
							bNodesAreValid = m_bWholeValid = false;
							break;
						}
						::safeRelease(pBoundNode);
					}

					*pbValid = bNodesAreValid ? VARIANT_TRUE : VARIANT_FALSE;
				} else {
					*pbValid = VARIANT_TRUE;
					hr = S_FALSE;
				}
			} else
				hr = E_INVALIDARG;
		} else {
			BOOL b = true;
			hr = valid(pNodeList, &b);
			if(SUCCEEDED(hr))
				*pbValid = b ? VARIANT_TRUE : VARIANT_FALSE;
		}
	} else
		hr = E_POINTER;

	return hr;
}
STDMETHODIMP CXmlState::validOrIrrelevant(IXMLDOMNodeList *pNodeList, VARIANT_BOOL bTestAllNodes, VARIANT_BOOL *pbValid)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	HRESULT hr = S_OK;

	if(pbValid) {
		if(bTestAllNodes == VARIANT_TRUE) {
			if(pNodeList) {
				if(m_bValidate != VARIANT_FALSE) {
					bool bNodesAreValid = true;

					long nNodes = 0;
					pNodeList->get_length(&nNodes);
					for(long i = 0; i < nNodes; ++i) {
						CBoundNode *pBoundNode = 0;
						if(GetBoundNode(pNodeList, i, pBoundNode) == S_OK && pBoundNode->isRelevant() && !pBoundNode->isValid()) {
							bNodesAreValid = m_bWholeValid = false;
#ifdef _DEBUG
							CComPtr<IXMLDOMNode> pNode;
							pNodeList->get_item(i, &pNode);
							if(pNode)
							{
								CComBSTR s;
								pNode->get_xml(&s);
								::MessageBoxW(0, s, L"formsPlayer: invalid node", MB_OK | MB_ICONERROR);
							}
#endif
							break;
						}
						::safeRelease(pBoundNode);
					}

					*pbValid = bNodesAreValid ? VARIANT_TRUE : VARIANT_FALSE;
				} else {
					*pbValid = VARIANT_TRUE;
					hr = S_FALSE;
				}
			} else
				hr = E_INVALIDARG;
		} else {
			BOOL b = true;
			hr = valid(pNodeList, &b);
			if(SUCCEEDED(hr))
				*pbValid = b ? VARIANT_TRUE : VARIANT_FALSE;
		}
	} else
		hr = E_POINTER;

	return hr;
}
